import datetime
from datetime import timedelta

from django.db.models import Q, Count
from django.db.models.aggregates import Min
from django.http import Http404
from django.utils import timezone
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
from django_filters.rest_framework import DjangoFilterBackend
from django_redis import get_redis_connection
from rest_framework import mixins, generics, viewsets, status
from rest_framework.decorators import api_view, action
from rest_framework.response import Response

from asset.serializers import trend_graph_serializer
from mongolog.models import CASLog, StrategyLog
from mongolog.utils import date_range
from tools.datetime import as_datetime, range_date
from tools.datetime import aware_localtime, date_filter
from tools.ipip import find_ip_location
from tools.utils import get_name_uid
from tools.decorators import reload_cas
from userdata.training.adapters import RedisAdapter
from userdata.training.anomaly import AnomalyDetection
from zmad.models import ZTPUser, ZTPGroup
from ztp_backend.permissions import IsUUIDPermission
from ztp_backend.settings import LEVEL_MAPPING, DEFAULT_PLATFORM
from .metadata import StrategyMetadata
from .models import (
    Strategy, LoginLocation,
    StrategyApplyRecord, SensitiveWord,
    SecretFile, StrategyGlobalAction, CreditGlobalAction, SafetyCreditEvaluation
)
from .serializers import (
    StrategySerializer, NewLoginLocationSerializer, NewLoginDeviceSerializer, StrategyTriggerSerializer,
    SensitiveWordSerializer, SecretFileSerializer,
    AnomalyDetectionSerializer, DeviceLoginLocationSerializer, StrategyGlobalActionSerializer,
    StrategyGlobalConfigSerializer, StrategyCreditGlobalSerializer, StrategyCreditConfigSerializer,
    StrategyCreditBasicSerializer
)


class StrategyCreditBasicViewSet(viewsets.ModelViewSet):
    queryset = SafetyCreditEvaluation.objects.all()
    serializer_class = StrategyCreditBasicSerializer
    filter_backends = (DjangoFilterBackend,)
    filterset_fields = ("module",)

    def list(self, request, *args, **kwargs):
        module = self.request.query_params.get('module', 1)
        unique_module = self.queryset.order_by('module').values_list('module', flat=True).distinct()
        module_list = list(unique_module)
        module_column = {num: desc for num, desc in SafetyCreditEvaluation.MODULE_MAPPING}
        module_weight = [{"module": desc, "a": 80, "b": 100} for num, desc in SafetyCreditEvaluation.MODULE_MAPPING]
        module_safe = [{"type": desc, "value": 20} for num, desc in SafetyCreditEvaluation.MODULE_MAPPING]
        serializer = self.get_serializer(self.filter_queryset(self.get_queryset().filter(module=module)), many=True)
        aggregated_data = {"module": module_column[int(module)], "module_weight": module_weight, "module_safe": module_safe}
        unit_info = list()
        level_score_dict = {1: 3, 2: 5, 3: 7}
        # 遍历数据，按module分组
        for item in serializer.data:
            module_ = item.get('module')
            # print(64, module_, module)
            if module_ == int(module):
                instance = Strategy.objects.filter(name=item.get('unit'), channel=4).first()
                unit_info.append({
                    'unit': item.get('unit'),
                    # 'score': item.get('score')
                    'score': level_score_dict[instance.level]
                })
                SafetyCreditEvaluation.objects.filter(unit=item.get('unit')).update(
                    score=level_score_dict[instance.level])
        aggregated_data['unit_info'] = unit_info
        if aggregated_data:
            return Response(aggregated_data, status=status.HTTP_200_OK)


@method_decorator(reload_cas, 'update_score')
class StrategyCreditScoreViewSet(viewsets.ModelViewSet):
    queryset = CreditGlobalAction.objects.all()
    serializer_class = StrategyCreditConfigSerializer
    filter_backends = (DjangoFilterBackend,)

    def list(self, request, *args, **kwargs):
        total = ZTPUser.objects.all().count()
        score_config = list()
        unique_score_list = self.queryset.order_by('score_upper').values_list('score_upper', flat=True).distinct()
        score_group = ZTPUser.objects.order_by('safety_score').values('safety_score').\
            annotate(count=Count('id', distinct=True))
        for query in score_group:
            score_config.append(
                {'score': query["safety_score"],
                 'value': round((query["count"] / total) * 100, 4)}
            )
        score_list = list(unique_score_list)
        data = {"score_region": score_list, "score_config": score_config}
        return Response(data, status=status.HTTP_200_OK)

    @action(detail=False, methods=['post'], url_path='update')
    def update_score(self, serializer):
        score_region = self.request.data.get('score_region', [])
        if not isinstance(score_region, list) or not all(isinstance(score, int) for score in score_region):
            return Response({"msg": "参数错误,应为整数递增长度为4的列表"}, status=status.HTTP_400_BAD_REQUEST)
        if len(score_region) == 4:
            CreditGlobalAction.objects.filter(level=3).update(score_upper=score_region[0])
            CreditGlobalAction.objects.filter(level=2).update(score_lower=score_region[0])
            CreditGlobalAction.objects.filter(level=2).update(score_upper=score_region[1])
            CreditGlobalAction.objects.filter(level=1).update(score_lower=score_region[1])
            CreditGlobalAction.objects.filter(level=1).update(score_upper=score_region[2])
            CreditGlobalAction.objects.filter(level=0).update(score_lower=score_region[2])
            CreditGlobalAction.objects.filter(level=0).update(score_upper=score_region[3])
        return Response(status=status.HTTP_200_OK)


@method_decorator(reload_cas, 'create')
class StrategyCreditGlobalViewSet(viewsets.ModelViewSet):
    queryset = CreditGlobalAction.objects.all()
    serializer_class = StrategyCreditConfigSerializer
    filter_backends = (DjangoFilterBackend,)
    filterset_fields = ('level', 'sen_mark', 'status', 'enabled')

    def list(self, request, *args, **kwargs):
        # 没有分页，序列化整个查询集
        serializer = self.get_serializer(self.filter_queryset(self.get_queryset()), many=True)
        enable_ = None
        for data_i in serializer.data:
            enable_ = data_i['enabled']
            break

        return Response({"enabled": enable_}, status=status.HTTP_200_OK)

    def perform_create(self, serializer):
        enabled = self.request.data.get('enabled', '')
        serializer = self.get_serializer(self.get_queryset(), many=True)
        if type(enabled) is bool:
            # 提取所有ID
            ids = [obj.id for obj in self.queryset]
            CreditGlobalAction.objects.filter(id__in=ids).update(enabled=enabled)
        return Response(serializer.data, status=status.HTTP_200_OK)


@method_decorator(reload_cas, 'update_status')
class StrategyCreditConfigViewSet(viewsets.ModelViewSet):

    queryset = CreditGlobalAction.objects.all()
    serializer_class = StrategyCreditGlobalSerializer
    # filter_backends = (DjangoFilterBackend,)
    # filterset_fields = ('level', 'action', 'status', 'enabled')

    def list(self, request, *args, **kwargs):
        unique_sen_mark = self.queryset.order_by('sen_mark').values_list('sen_mark', flat=True).distinct()
        sen_mark_list = list(unique_sen_mark)
        STRATEGY_LEVELS_DICT = {num: desc for num, desc in CreditGlobalAction.TRIGGER_ACTION}
        sen_mark_list = [STRATEGY_LEVELS_DICT[num] for num in sen_mark_list]
        TYPE_DICT = {num: desc for num, desc in CreditGlobalAction.CONFIG_TYPE}
        # 序列化整个查询集
        serializer = self.get_serializer(self.filter_queryset(self.get_queryset()).order_by('sen_mark'), many=True)
        result = list()
        for sen_mark in STRATEGY_LEVELS_DICT.keys():
            if sen_mark in [1, 2, 3]:
                level_dict = {'desc': STRATEGY_LEVELS_DICT[sen_mark], "type": TYPE_DICT[1]}
            else:
                level_dict = {'desc': STRATEGY_LEVELS_DICT[sen_mark], "type": TYPE_DICT[2]}
            for data_ in serializer.data:
                if sen_mark == int(data_.get("sen_mark")):
                    if data_.get("level") == 3 and data_.get("config_type") == 1:
                        level_dict["high"] = {"id": data_.get('id'), "status": data_.get('status')}
                    elif data_.get("level") == 2 and data_.get("config_type") == 1:
                        level_dict["middle"] = {"id": data_.get('id'), "status": data_.get('status')}
                    elif data_.get("level") == 1 and data_.get("config_type") == 1:
                        level_dict["low"] = {"id": data_.get('id'), "status": data_.get('status')}
                    elif data_.get("level") == 0 and data_.get("config_type") == 1:
                        level_dict["safe"] = {"id": data_.get('id'), "status": data_.get('status')}
                elif sen_mark == int(data_.get("sen_mark"))+3:
                    if data_.get("level") == 3 and data_.get("config_type") == 2:
                        level_dict["high"] = {"id": data_.get('id'), "status": data_.get('status')}
                    elif data_.get("level") == 2 and data_.get("config_type") == 2:
                        level_dict["middle"] = {"id": data_.get('id'), "status": data_.get('status')}
                    elif data_.get("level") == 1 and data_.get("config_type") == 2:
                        level_dict["low"] = {"id": data_.get('id'), "status": data_.get('status')}
                    elif data_.get("level") == 0 and data_.get("config_type") == 2:
                        level_dict["safe"] = {"id": data_.get('id'), "status": data_.get('status')}

            result.append(level_dict)
        return Response({"data": result}, status=status.HTTP_200_OK)

    @action(detail=False, methods=['post'], url_path='update')
    def update_status(self, request, *args, **kwargs):
        ids = self.request.data.get('ids', [])
        if not isinstance(ids, list) or not all(isinstance(id_, dict) for id_ in ids):
            return Response({"msg": "参数错误,ids应为字典的列表"}, status=status.HTTP_400_BAD_REQUEST)
        for id_info in ids:
            CreditGlobalAction.objects.filter(id=id_info.get("id")).update(status=id_info.get("status"))
        # 返回响应
        return Response(status=status.HTTP_200_OK)


@method_decorator(reload_cas, 'update_status')
class StrategyGlobalConfigViewSet(viewsets.ModelViewSet):

    queryset = StrategyGlobalAction.objects.all()
    serializer_class = StrategyGlobalConfigSerializer
    # filter_backends = (DjangoFilterBackend,)
    # filterset_fields = ('level', 'action', 'status', 'enabled')

    def list(self, request, *args, **kwargs):
        unique_levels = self.queryset.order_by('-level').values_list('level', flat=True).distinct()
        level_list = list(unique_levels)
        # 序列化整个查询集
        serializer = self.get_serializer(self.filter_queryset(self.get_queryset()).order_by('action'), many=True)
        result = list()
        for level in level_list:
            level_dict = {'level': LEVEL_MAPPING.get(level)}
            strategies = list()
            for data_ in serializer.data:
                if level == data_['level']:
                    strategy = dict()
                    strategy["id"] = data_['id']
                    strategy["action_period_global"] = data_['action_period']
                    strategy["desc"] = data_['action']
                    strategy["status"] = data_['status']
                    strategies.append(strategy)
            level_dict['strategies'] = strategies
            result.append(level_dict)
        return Response({"data": result}, status=status.HTTP_200_OK)

    @action(detail=False, methods=['post'], url_path='update-status', url_name='strategy-global-update-status')
    def update_status(self, request, *args, **kwargs):
        ids_info = self.request.data.get('ids', [])
        ids = []
        if not isinstance(ids_info, list) or not all(
                isinstance(item, dict) and
                'id' in item and isinstance(item['id'], int) and
                'action_period_global' in item and isinstance(item['action_period_global'], int)
                for item in ids_info
        ):
            return Response({"msg": "参数错误,ids应为包含id和trigger_period字段的字典列表"}, status=status.HTTP_400_BAD_REQUEST)
        for data in ids_info:
            id, action_period = data.get('id'), data.get('action_period_global', 60)
            ids.append(id)
            StrategyGlobalAction.objects.filter(id=id).update(status=1, action_period=action_period)

        # 重置不在ids列表中的项的status为0
        # StrategyGlobalAction.objects.exclude(id__in=ids).exclude(action=0).update(status=0)
        StrategyGlobalAction.objects.exclude(id__in=ids).update(status=0)

        # 返回响应
        return Response(status=status.HTTP_200_OK)


@method_decorator(reload_cas, 'update')
class StrategyGlobalActionViewSet(viewsets.ModelViewSet):
    """
    策略视图类
    """
    queryset = StrategyGlobalAction.objects.all()
    serializer_class = StrategyGlobalActionSerializer
    filter_backends = (DjangoFilterBackend,)
    filterset_fields = ('level', 'action', 'status', 'enabled')

    def list(self, request, *args, **kwargs):
        # 没有分页，序列化整个查询集
        serializer = self.get_serializer(self.filter_queryset(self.get_queryset()), many=True)
        enable_ = None
        for data_i in serializer.data:
            enable_ = data_i['enabled']
            break

        return Response({"enabled": enable_}, status=status.HTTP_200_OK)

    def perform_create(self, serializer):
        enabled = self.request.data.get('enabled', '')
        serializer = self.get_serializer(self.get_queryset(), many=True)
        if type(enabled) is bool:
            # 提取所有ID
            ids = [obj.id for obj in self.queryset]
            for id_ in ids:
                instance = StrategyGlobalAction.objects.filter(id=id_).first()
                instance.enabled = enabled
                instance.save()

        return Response(serializer.data, status=status.HTTP_200_OK)


@method_decorator(reload_cas, 'update')
class StrategyViewSet(mixins.ListModelMixin,
                      mixins.UpdateModelMixin,
                      mixins.RetrieveModelMixin,
                      viewsets.GenericViewSet):
    """
    策略视图类
    """
    queryset = Strategy.objects.filter(category__in=StrategyMetadata.get_categories()).order_by('pk')
    serializer_class = StrategySerializer
    filter_backends = (DjangoFilterBackend,)
    filterset_fields = ('category', 'level', 'channel', 'name')
    metadata_class = StrategyMetadata

    def list(self, request, *args, **kwargs):
        # 没有分页，序列化整个查询集
        serializer = self.get_serializer(self.filter_queryset(self.get_queryset()), many=True)
        channel_str_tuple = Strategy.STRATEGY_CHANNELS
        level_str_tuple = Strategy.STRATEGY_LEVELS
        data_new = list()
        for data_i in serializer.data:
            channel_str = channel_str_tuple[data_i["channel"]][1]
            level_str = level_str_tuple[data_i["level"] - 1][1]
            options = []
            action_options = []
            trigger_options = []
            if data_i["uid"] in ['STG/HOSTAUDIT-1', 'STG/HOSTAUDIT-2']:
                options = [{'value': 0, 'label': '硬件资产'}, {'value': 1, 'label': '软件资产'},
                 {'value': 2, 'label': '硬件和软件资产'}],
            elif data_i["uid"] in ['STG/AUTH-5', 'STG/AUTH-27', 'STG/AUTH-28', 'STG/AUTH-36']:
                # options = [{'value': 3, 'label': '短信二次认证'}, {'value': 9, 'label': '禁止登录'}],
                options = [{'value': 3, 'label': '短信二次认证'}, {'value': 6, 'label': '本次禁止登录'}],  # 禁止登录 名称统一
            elif data_i["uid"] in ['STG/TERM-2', 'STG/TERM-5', 'STG/TERM-6', 'STG/TERM-7']:
                options = [{'value': 6, 'label': '本次禁止登录'}, {'value': 7, 'label': '提示用户'}],
            elif data_i["uid"] in ['STG/CONF-2', 'STG/REALTIMEPRO-1', 'STG/REALTIMEPRO-2', 'STG/REALTIMEPRO-3',
                                 'STG/REALTIMEPRO-4', 'STG/REALTIMEPRO-5', 'STG/REALTIMEPRO-6', 'STG/REALTIMEPRO-7',
                                 'STG/REALTIMEPRO-8', 'STG/REALTIMEPRO-9']:
                options = [{'value': 0, 'label': '手动'}, {'value': 1, 'label': '自动'}],
            elif data_i["uid"] in ['STG/CONF-1']:
                options = [20, 500]
            elif data_i["uid"] in ['STG/RES-1', 'STG/RES-5', 'STG/RES-6', 'STG/RES-7']:
                options = [50, 500]
            elif data_i["uid"] in ['STG/RES-3', 'STG/RES-11', 'STG/RES-12', 'STG/RES-13']:
                action_options = [10000, 100000]
                options = [1, 9999]
            elif data_i["uid"] in ['STG/RES-4', 'STG/RES-14', 'STG/RES-15', 'STG/RES-16']:
                options = [1, 9999]
            elif data_i["uid"] in ['STG/PERIPHERAL-1', 'STG/PERIPHERAL-2', 'STG/PERIPHERAL-3', 'STG/PERIPHERAL-4', 'STG/PERIPHERAL-5']:
                options = [{'value': 0, 'label': '允许使用'}, {'value': 1, 'label': '禁止使用'}, {'value': 2, 'label': '只读'}],
            elif data_i["uid"] in ['STG/TERM-3', 'STG/TERM-4']:
                options = [{'value': 6, 'label': '本次禁止登录'}, {'value': 8, 'label': '生成并记录风险日志'}],
            elif data_i["uid"] in ['STG/CONF-4', 'STG/CONF-5', 'STG/CONF-6']:
                options = [{'value': 0, 'label': '快速'}, {'value': 1, 'label': '全盘'}],
            elif data_i["uid"] in ['STG/CONF-3']:
                options = [{'value': 0, 'label': '高速'}, {'value': 1, 'label': '标准'}]
            elif data_i["uid"] in ['STG/TERM-13', 'STG/CONF-7', 'STG/CONF-8', 'STG/CONF-9']:
                options = [{'value': 0, 'label': '分钟'}, {'value': 1, 'label': '小时'}, {'value': 2, 'label': '天'}]
            elif data_i["uid"] in ['STG/CONF-10', 'STG/CONF-11', 'STG/CONF-12', 'STG/CONF-13']:
                options = [1, 5]
            elif data_i["uid"] in ['STG/AUTH-2', 'STG/AUTH-23', 'STG/AUTH-24', 'STG/AUTH-34']:
                trigger_options = [1, 720]  # 单次认证失效  时长取值范围
            elif data_i["uid"] in ['STG/AUTH-3', 'STG/AUTH-25', 'STG/AUTH-26', 'STG/AUTH-35']:
                trigger_options = [30, 720]  # 闲时登出  时长取值范围
            elif data_i["uid"] in ['STG/AUTH-13', 'STG/AUTH-14', 'STG/AUTH-15', 'STG/AUTH-33']:
                trigger_options = [0, 720]  # 认证失败冻结  时长取值范围
            elif data_i["uid"] in ["STG/AUTH-16", "STG/AUTH-17", "STG/AUTH-18", "STG/AUTH-32"]:
                trigger_options = [0, 720]  # 二次认证冻结  时长取值范围
            if len(options) == 1:
                options = options[0]
            data_i.update({"options": options, "channel_str": channel_str, "level_str": level_str,
                           "action_options": action_options, "trigger_options": trigger_options})
            data_new.append(data_i)

        return Response(data_new, status=status.HTTP_200_OK)

    def update(self, request, *args, **kwargs):
        current_url = request.build_absolute_uri()
        instance_id = current_url.split('/')[-1]
        instance = Strategy.objects.filter(id=instance_id).first()
        if instance:
            uid = instance.uid
            request.data['uid'] = uid
            # update 的字段不符合规范，则返回如下消息
            res = Response({"uid": uid, "detail": "该处理方式不符合规范", "data": {}},
                           status=status.HTTP_406_NOT_ACCEPTABLE
                           )
            # 对 update 的策略字段进行校验
            # 异常登录的处理
            if uid in ['STG/AUTH-5', 'STG/AUTH-27', 'STG/AUTH-28']:
                action = self.request.data.get('action', 3)
                if action not in [3, 9]:
                    return res
            # 检出恶意APK处置，检出钓鱼URL处置, 检出访问钓鱼URL处置, 检出访问恶意WiFi处置
            if uid in ['STG/TERM-2', 'STG/TERM-5', 'STG/TERM-6', 'STG/TERM-7']:
                action = self.request.data.get('action', 7)
                if action not in [6, 7]:
                    return res
            # 检出风险APK处置, 检出敏感APK处置
            if uid in ['STG/TERM-3', 'STG/TERM-4']:
                action = self.request.data.get('action', 8)
                if action not in [6, 8]:
                    return res
            # 定时检测周期
            if uid in ['STG/TERM-13']:
                num_value = self.request.data.get('num_value', 60)
                if num_value not in range(0, 360 + 1):
                    return res
            # 图形验证码启用
            if uid in ['STG/CONF-10', 'STG/CONF-11', 'STG/CONF-12', 'STG/CONF-13']:
                trigger_times = self.request.data.get('trigger_times', None)
                enabled = self.request.data.get('enabled', "")
                if trigger_times is not None and trigger_times not in range(1, 5 + 1):
                    return res
                else:
                    uid_list = get_name_uid(instance.name)
                    uid_queryset = Strategy.objects.filter(uid__in=uid_list).all()
                    for uid_queryset_i in uid_queryset:
                        if trigger_times is not None:
                            uid_queryset_i.trigger_times = trigger_times
                        if type(enabled) is bool:
                            uid_queryset_i.enabled = enabled
                        uid_queryset_i.save()
            # ####################### 多端策略参数修改联动处理
            # Linux端二次认证相关策略开启联动   f'{CATEGORY_BASECONFIG[1]}-17'， f'{CATEGORY_AUTH[1]}-32'
            if uid in ['STG/CONF-17', 'STG/AUTH-32']:
                enabled = self.request.data.get('enabled', "")
                uid_list = list(['STG/CONF-17', 'STG/AUTH-32'])
                uid_queryset = Strategy.objects.filter(uid__in=uid_list).all()
                for uid_queryset_i in uid_queryset:
                    if type(enabled) is bool:
                        uid_queryset_i.enabled = enabled
                    uid_queryset_i.save()
            # Linux客户端持续检测设置 策略关闭，则（持续恶意代码检测，持续入侵检测，持续漏洞检测）三个策略同步关闭
            if uid in ('STG/CONF-9', ):
                enabled = self.request.data.get('enabled', "")
                if enabled is False:
                    uid_list = ['STG/TERM-10', 'STG/TERM-11', 'STG/TERM-12']
                    uid_queryset = Strategy.objects.filter(uid__in=uid_list).all()
                    for uid_queryset_i in uid_queryset:
                        if type(enabled) is bool:
                            uid_queryset_i.enabled = enabled
                        uid_queryset_i.save()
            # 资源请求频次过高
            if uid in ['STG/RES-1', 'STG/RES-5', 'STG/RES-6', 'STG/RES-7']:
                num_value = self.request.data.get('num_value', 100)
                enabled = self.request.data.get('enabled', "")
                level = self.request.data.get('level', "")
                if num_value not in range(50, 500 + 1):
                    return res
                else:
                    uid_list = get_name_uid(instance.name)
                    uid_queryset = Strategy.objects.filter(uid__in=uid_list).all()
                    for uid_queryset_i in uid_queryset:
                        uid_queryset_i.num_value = num_value
                        if type(enabled) is bool:
                            uid_queryset_i.enabled = enabled
                        if level:
                            uid_queryset_i.level = level
                        uid_queryset_i.save()
            # 资源请求越权
            if uid in ['STG/RES-2', 'STG/RES-8', 'STG/RES-9', 'STG/RES-10']:
                enabled = self.request.data.get('enabled', "")
                level = self.request.data.get('level', "")
                uid_list = get_name_uid(instance.name)
                uid_queryset = Strategy.objects.filter(uid__in=uid_list).all()
                for uid_queryset_i in uid_queryset:
                    if type(enabled) is bool:
                        uid_queryset_i.enabled = enabled
                    if level:
                        uid_queryset_i.level = level
                    uid_queryset_i.save()
            # 资源请求总量
            if uid in ['STG/RES-3', 'STG/RES-11', 'STG/RES-12', 'STG/RES-13']:
                action_times = self.request.data.get('action_times', 100000)
                num_value = self.request.data.get('num_value', 120)
                enabled = self.request.data.get('enabled', "")
                level = self.request.data.get('level', "")
                if action_times not in range(10000, 100000 + 1) or num_value not in range(1, 9999 + 1):
                    return res
                else:
                    uid_list = get_name_uid(instance.name)
                    uid_queryset = Strategy.objects.filter(uid__in=uid_list).all()
                    for uid_queryset_i in uid_queryset:
                        uid_queryset_i.action_times = action_times
                        uid_queryset_i.num_value = num_value
                        if type(enabled) is bool:
                            uid_queryset_i.enabled = enabled
                        if level:
                            uid_queryset_i.level = level
                        uid_queryset_i.save()
            # # 当日资源请求异常,用户冻结时间
            if uid in ['STG/RES-4', 'STG/RES-14', 'STG/RES-15', 'STG/RES-16']:
                num_value = self.request.data.get('num_value', 15)
                enabled = self.request.data.get('enabled', "")
                level = self.request.data.get('level', "")
                if num_value not in range(1, 9999 + 1):
                    return res
                else:
                    uid_list = get_name_uid(instance.name)
                    uid_queryset = Strategy.objects.filter(uid__in=uid_list).all()
                    for uid_queryset_i in uid_queryset:
                        uid_queryset_i.num_value = num_value
                        if type(enabled) is bool:
                            uid_queryset_i.enabled = enabled
                        if level:
                            uid_queryset_i.level = level
                        uid_queryset_i.save()

        level = self.request.data.get('level', "")
        uid_queryset_ = Strategy.objects.filter(uid=uid).first()
        if level and 'STG/RES-' not in uid:
            uid_queryset_.level = level
            uid_queryset_.save()

        return super().update(request, *args, **kwargs)


class DeviceLoginLocationView(generics.GenericAPIView):
    # queryset = LoginLocation.objects.all()
    permission_classes = (IsUUIDPermission,)

    def post(self, request, *args, **kwargs):
        serializer = DeviceLoginLocationSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        device_uuid = serializer.validated_data['device_uuid']
        client_ip = serializer.validated_data['client_ip']
        ip_location = find_ip_location(client_ip) or {}

        data = {
            'device_uuid': device_uuid,
            'country': ip_location.get('country_name', ''),
            'region': ip_location.get('region_name', ''),
            'city': ip_location.get('city_name', ''),
            'new_location': self.check_device_location(device_uuid, ip_location)
        }
        return Response(data)

    @classmethod
    def check_device_location(cls, device_uuid, ip_location):
        if not ip_location:
            return True

        country = ip_location['country_name']
        city = ip_location['city_name']

        if country == '局域网':
            return False
        device_most_location = cls.device_most_common_location(device_uuid)
        print(device_most_location)
        if not device_most_location:
            return False
        if city != device_most_location:
            return True
        return False

    @classmethod
    def device_most_common_location(cls, device_uuid, dt_begin='', dt_end=''):
        # 计算设备的最多登录地址(城市)
        match = date_range('log_time', dt_begin, dt_end)
        aggregate = [{
            '$project': {
                'location': {
                    '$concat': [
                        '$ip_location.city_name',
                    ]
                }
            }
        },
            {'$sortByCount': '$location'},
            {'$limit': 1}]
        match['device_uuid'] = device_uuid
        match['ip_location.country_name'] = {'$exists': True, '$ne': '局域网'}
        aggregate.insert(0, {'$match': match})
        aggregate.append({
            "$project": {
                "_id": 1,
                "location": "$_id",
                "count": 1
            }}
        )
        print(aggregate)
        queryset = CASLog.objects.mongo_aggregate(aggregate)
        try:
            res = next(queryset)
            return res['location']
        except StopIteration:
            return None


class NewLoginLocationView(generics.GenericAPIView):
    """STG/DEVICE 设备异地登录策略判断视图类"""
    queryset = LoginLocation.objects.all()
    permission_classes = (IsUUIDPermission,)

    def post(self, request, *args, **kwargs):
        serializer = NewLoginLocationSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        username = serializer.validated_data['username']
        client_ip = serializer.validated_data['client_ip']
        ip_location = find_ip_location(client_ip) or {}

        data = {
            'username': username,
            'country': ip_location.get('country_name', ''),
            'region': ip_location.get('region_name', ''),
            'city': ip_location.get('city_name', ''),
            'new_location': self.update_new_location(username, ip_location),
        }
        return Response(data)

    def update_new_location(self, username, ip_location):
        """异地登录判断
        算法：
        将用户的登录历史分为三个层级
        1.上次登录地点last_location及时间last_time
        2.最近一周最常用登录地点weekly_location，下次更新该地点的时间weekly_expiration
        3.最近一个月最常用登录地点monthly_location，下次更新该地点的时间monthly_expiration
        本次登陆时，传递用户名及登录IP，通过IPDB数据库取得IP所在地
        若IP所在地无法识别，直接返回异地登录
        若IP所在地为局域网，直接返回非异地登录
        否则，通过用户名取得该用户登录历史
        若无登录历史，新增记录：
        1.填充username=当前用户名，last_location=当前IP所在地，last_time=当前时间
        2.填充weekly_expiration为当前时间+3天
        3.填充monthly_expiration为当前时间+15天
        否则，比对本次登录的IP所在地和历史记录：
        1.IP所在地和last_location相同，返回非异地登录，否则进入2
        2.若当前时间大于weekly_expiration，以last_time前7天为基准更新weekly_location，并更新weekly_expiration为当前时间+3天
        3.IP所在地和weekly_location相同，返回非异地登录，否则进入4
        4.若当前时间大于monthly_expiration，以last_time前30天为基准更新monthly_location，并更新monthly_expiration为当前时间+15天
        5.IP所在地和monthly_location相同，返回非异地登录，否则返回异地登录
        6.更新last_location及last_time
        :arg username: 用户名
        :arg ip_location: IPIP地理位置字典
        :return: True 异地登录 False 非异地登录
        """
        if not ip_location:
            return True

        country = ip_location['country_name']
        region = ip_location['region_name']
        city = ip_location['city_name']

        if country == '局域网':
            return False

        now = timezone.now()
        location = '-'.join((country, region, city))
        try:
            instance = LoginLocation.objects.get(username=username)
            last_location = instance.last_location
            instance.last_location = location

            # 第一层比较
            if self.same_location(location, last_location):
                # last_time字段自动更新
                instance.save()
                return False

            # 第二层比较
            if now > instance.weekly_expiration:
                instance.weekly_location = self.most_common_location(
                    username=username,
                    dt_begin=instance.last_time - timedelta(days=7),
                    dt_end=instance.last_time
                )
                instance.weekly_expiration = now + timedelta(days=3)
            if self.same_location(location, instance.weekly_location):
                instance.save()
                return False

            # 第三层比较
            if now > instance.monthly_expiration:
                instance.monthly_location = self.most_common_location(
                    username=username,
                    dt_begin=instance.last_time - timedelta(days=30),
                    dt_end=instance.last_time
                )
                instance.monthly_expiration = now + timedelta(days=15)
            instance.save()
            return not self.same_location(location, instance.monthly_location)
        except LoginLocation.DoesNotExist:
            # 检查用户是否存在
            if not ZTPUser.objects.filter(username=username).exists():
                raise Http404

            LoginLocation.objects.create(
                username=username,
                last_location=location,
                weekly_expiration=now + timedelta(days=3),
                monthly_expiration=now + timedelta(days=15),
            )
            return False

    @classmethod
    def same_location(cls, loc1, loc2):
        """比较两个地址是否相同，满足以下任意条件即视为相同地址
        1.两个地址的国家-省州-城市完全一样
        2.一个地址包含另一个地址（如「中国-湖北」和「中国-湖北-武汉」）
        """
        if not loc1 or not loc2:
            return False

        if loc1 == loc2:
            return True

        loc1, loc2 = loc1.split('-'), loc2.split('-')
        for i in range(min(len(loc1), len(loc2), 3)):
            if loc1[i] and loc2[i]:
                if loc1[i] != loc2[i]:
                    return False
            else:
                return True
        return True

    @classmethod
    def most_common_location(cls, username, dt_begin, dt_end):
        queryset = CASLog.objects.mongo_aggregate([
            {
                '$match': {
                    'username': username,
                    'ip_location.country_name': {
                        '$exists': True,
                        '$ne': '局域网',
                    },
                    'log_time': {
                        '$gte': dt_begin,
                        '$lte': dt_end
                    }
                }
            },
            {
                '$project': {
                    'location': {
                        '$concat': [
                            '$ip_location.country_name',
                            '-',
                            '$ip_location.region_name',
                            '-',
                            '$ip_location.city_name',
                        ]
                    }
                }
            },
            {'$sortByCount': '$location'},
            {'$limit': 1},
            {
                "$project": {
                    "_id": 1,
                    "location": "$_id",
                    "count": 1
                }}
        ])
        try:
            return next(queryset)['location']
        except StopIteration:
            return None


class NewLoginDeviceView(generics.GenericAPIView):
    """STG/TERM-1新设备登录策略判断视图类"""
    serializer_class = NewLoginDeviceSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        username = serializer.validated_data['username']
        # imei = serializer.validated_data['imei']
        uuid = serializer.validated_data['uuid']
        query = CASLog.objects.filter(username=username)
        if not query.exists():
            new_device = False
        else:
            new_device = not CASLog.objects.filter(
                username=username, auth_result='AUTH_SUCCESS', device_fingerprint={'uuid': uuid}
            ).exists()

        data = {'username': username, 'new_device': new_device}
        return Response(data)


class AnomalyDetectionView(generics.GenericAPIView):
    """STG/RES-4当日资源请求异常策略判断视图类"""
    serializer_class = AnomalyDetectionSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        username = serializer.validated_data['username']

        adapter = RedisAdapter(get_redis_connection('anomaly_detection'))
        ad_model = AnomalyDetection(max_data=100, min_data=1, outlier=500, adapter=adapter)

        data = {'username': username, 'score': ad_model.detection(username)}
        return Response(data)


# @cache_page(60 * 10)
@api_view(['GET'])
def strategy_trigger_count(request):
    """策略触发总数"""
    since_queryset = StrategyLog.objects.mongo_aggregate([
        {
            '$group': {
                '_id': None,
                'since': {'$min': '$log_time'}
            }
        }
    ])
    try:
        since = aware_localtime(next(since_queryset)['since']).date()
    except StopIteration:
        since = datetime.date.today()

    total = StrategyLog.objects.count()

    today = StrategyLog.objects.filter(log_time=datetime.date.today()).count()

    data = {'since': since, 'total': total, 'today': today}
    return Response(data)


@cache_page(60 * 10)
@api_view(['GET'])
def strategy_dispatch_count(request):
    """策略下发总数"""
    since = StrategyApplyRecord.objects.aggregate(since=Min('apply_time'))['since'] or timezone.now()

    total = StrategyApplyRecord.objects.count()

    today = StrategyApplyRecord.objects.filter(apply_time__date=datetime.date.today()).count()

    data = {
        'since': aware_localtime(since).date(),
        'total': total,
        'today': today
    }
    return Response(data)


@cache_page(60 * 10)
@api_view(['GET'])
def strategy_trigger_trend(request):
    """策略触发情况趋势图"""
    date_from, date_to = date_filter(request.query_params)
    data = trend_graph_serializer(
        StrategyLog, 'meta.category',
        **date_range('log_time', date_from, date_to)
    )
    return Response(data)


# # @cache_page(60 * 10)
# @api_view(['GET'])
# def strategy_risk_level_old(request):
#     """策略危险等级分布情况"""
#     date_from, date_to = date_filter(request.query_params)
#     channel = request.query_params.get('channel') or DEFAULT_PLATFORM
#     match = date_range('log_time', date_from, date_to)
#     aggregations = [
#         {
#             '$group': {
#                 '_id': '$meta.level',
#                 'count': {'$sum': 1}
#             }
#         },
#         {'$sort': {'_id': 1}}
#     ]
#     if match:
#         aggregations.insert(0, {'$match': match})
#     if channel:
#         aggregations.insert(0, {'$match': {'platform': int(channel)}})
#
#     queryset = StrategyLog.objects.mongo_aggregate(aggregations)
#
#     level_dict = dict(Strategy.STRATEGY_LEVELS)
#
#     data = [{'level': agg['_id'], 'name': level_dict[agg['_id']], 'count': agg['count']} for agg in queryset]
#     return Response(data)


@api_view(['GET'])
def strategy_risk_level(request):
    """策略危险等级分布情况"""
    date_from, date_to = date_filter(request.query_params)
    channel = request.query_params.get('channel') or DEFAULT_PLATFORM
    match = date_range('log_time', date_from, date_to)
    aggregations = [
        {'$match': {
            'username': {'$exists': True},
            }
        },
        {
            '$group': {
                '_id': '$uid',
                'count': {'$sum': 1}
            }
        },
        {'$sort': {'_id': 1}}
    ]
    if match:
        aggregations.insert(0, {'$match': match})
    if channel:
        aggregations.insert(0, {'$match': {'platform': int(channel)}})

    queryset = StrategyLog.objects.mongo_aggregate(aggregations)
    level_dict = dict(Strategy.STRATEGY_LEVELS)
    stguid2level = dict(Strategy.objects.values_list('uid', 'level'))
    level_dict_new = {}
    level_dict_keys = list(level_dict.keys())
    for level_ in level_dict_keys:
        level_dict_new[level_] = []

    # 获取每个策略uid对应威胁等级的数量
    for agg in queryset:
        level_dict_new[stguid2level[agg['_id']]].append(agg['count'])

    data = [{'level': i, 'name': level_dict[i], 'count': sum(level_dict_new[i])} for i in list(level_dict.keys())]

    return Response(data)


# @method_decorator(cache_page(60 * 10), name='list')
class StrategyTriggerViewSet(mixins.ListModelMixin,
                             mixins.RetrieveModelMixin,
                             viewsets.GenericViewSet):
    """
    策略触发总览视图类
    """
    queryset = Strategy.objects.filter(category__in=StrategyMetadata.get_categories()).order_by('pk')
    serializer_class = StrategyTriggerSerializer
    metadata_class = StrategyMetadata
    filter_backends = (DjangoFilterBackend,)
    filterset_fields = ('category', 'level', 'channel')

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        serializer = self.get_serializer(queryset, many=True)
        data = list(serializer.data)
        strategy_counts = dict(((agg.pop('_id'), agg) for agg in self.get_mongo_queryset()))
        channel_str_tuple = Strategy.STRATEGY_CHANNELS
        for r in data:
            c = strategy_counts.get(r['uid'], {})
            r['trigger_count'] = c.get('trigger_count', 0)
            # r['affected_user'] = c.get('affected_user', 0)
            usernames = c.get("usernames", [])
            r["affected_user"] = ZTPUser.objects.filter(username__in=usernames).count()
            channel_str = channel_str_tuple[r["channel"]][1]
            r["channel_str"] = channel_str

        data_new = list()
        for r in data:
            if r['trigger_count'] != 0:
                data_new.append(r)
        data = data_new
        # 支持trigger_count和affected_user排序
        sort = self.request.query_params.get('ordering')
        if sort:
            if sort.startswith('-'):
                rev = True
                sort = sort[1:]
            else:
                rev = False
            if sort in ('trigger_count', 'affected_user'):
                data.sort(key=lambda x: x.get(sort), reverse=rev)

        page = self.paginate_queryset(data)
        if page is not None:
            return self.get_paginated_response(page)
        return Response(data)

    def get_mongo_queryset(self):
        aggregation = [
            {
                '$group': {
                    '_id': '$uid',
                    'usernames': {'$addToSet': '$username'},
                    'trigger_count': {'$sum': 1}
                }
            },
            {
                '$project': {
                    'trigger_count': 1,
                    'affected_user': {'$size': '$usernames'},
                    "usernames": "$usernames"
                }
            }
        ]
        date_from, date_to = date_filter(self.request.query_params)

        channel = self.request.query_params.get('channel') or DEFAULT_PLATFORM
        if channel:
            aggregation.insert(0, {'$match': {'platform': int(channel)}})

        match = date_range('log_time', date_from, date_to)
        if match:
            aggregation.insert(0, {'$match': match})

        queryset = StrategyLog.objects.mongo_aggregate(aggregation)
        return queryset


class SensitiveWordViewSet(viewsets.ModelViewSet):
    """
    敏感词增删改查视图类
    """
    queryset = SensitiveWord.objects.all()
    serializer_class = SensitiveWordSerializer


class SecretFileViewSet(viewsets.ModelViewSet):
    """
    密级文件增删改查视图类
    """
    queryset = SecretFile.objects.all()
    serializer_class = SecretFileSerializer


@api_view(["GET"])
def strategy_trend(request):
    channel = request.GET.get('channel') or DEFAULT_PLATFORM
    pipeline = StrategyLog.objects.mongo_aggregate([
        {'$match': {
            'username': {'$exists': True},
            'platform': {'$exists': True}  # 这里需要过滤
        }},
        {'$project': {
            'platform': 1,
            'log_time': 1  # 确保 log_time 在这里被投影，尽管在后续步骤中只使用其年、月、日部分
        }},
        {'$project': {
            'platform': 1,
            'year': {'$year': '$log_time'},
            'month': {'$month': '$log_time'},
            'day': {'$dayOfMonth': '$log_time'}
        }},
        {'$group': {
            '_id': {'platform': '$platform', 'year': '$year', 'month': '$month', 'day': '$day'},
            'num': {'$sum': 1}
        }},
        {'$sort': {
            '_id.year': 1,
            '_id.month': 1,
            '_id.day': 1
        }},
        {'$project': {
            '_id': 0,
            'platform': '$_id.platform',
            'date': {'$concat': [
                {'$toString': '$_id.year'}, '-',
                {'$toString': '$_id.month'}, '-',
                {'$toString': '$_id.day'}
            ]},
            'num': 1
        }}
    ])
    # todo 根据strategy 的uid来确认平台platform， 排除platform可能为空导致统计不准的情况。
    queryset = [{"date": agg["date"], "num":agg["num"], "platform":agg["platform"]} for agg in pipeline]
    if len(queryset) == 0:
        return Response({"data": []}, status=status.HTTP_200_OK)
    date_from = queryset[0].get("date")
    date_from = datetime.datetime.strptime(date_from, '%Y-%m-%d').date()
    date_to = datetime.date.today()
    data = []
    # print(937, date_from, date_to)
    channel_to_str = {1: 'Android', 2: 'Windows', 3: 'Web', 4: 'Linux'}
    for date in range_date(date_from, date_to):
        if channel and channel_to_str.get(int(channel)):
            agg_dict = {"date": str(date)}
            agg_dict[channel_to_str.get(int(channel))] = 0
        else:
            agg_dict = {"date": str(date), "Android": 0, "Windows": 0, "Web": 0, "Linux": 0, }
        for agg in queryset:
            agg_date = datetime.datetime.strptime(agg['date'], '%Y-%m-%d').date()
            if date == agg_date:
                if agg["platform"] == 1 and (agg_dict.get('Android') is not None):
                    agg_dict["Android"] = agg["num"]
                elif agg["platform"] == 2 and (agg_dict.get('Windows') is not None):
                    agg_dict["Windows"] = agg["num"]
                elif agg["platform"] == 3 and (agg_dict.get('Web') is not None):
                    agg_dict["Web"] = agg["num"]
                elif agg["platform"] == 4 and (agg_dict.get('Linux') is not None):
                    agg_dict["Linux"] = agg["num"]
        data.append(agg_dict)

    # 对策略当日触发数量进行修正，因为时区问题，今日数据如果基于  datetime.datetime.strptime(date_from, '%Y-%m-%d').date()
    # 计算会不准,会有 8 小时时差
    date_now = datetime.datetime.now()
    today_date_from = as_datetime(date_now.replace(hour=0, minute=0, second=0, microsecond=0))
    date_to = date_now.replace(hour=23, minute=59, second=59, microsecond=999)
    if channel:
        today_total_count = StrategyLog.objects.filter(log_time__gt=today_date_from,
                                                       log_time__lt=date_to,
                                                       platform=channel).count()
        data[-1][channel_to_str[channel]] = today_total_count

    return Response({"data": data}, status=status.HTTP_200_OK)


@api_view(["GET"])
def strategy_screening(request):
    date_from, date_to = date_filter(request.query_params)
    platform = request.query_params.get("channel")
    match = {}
    if date_from and date_to:
        match = date_range('log_time', date_from, date_to)
    if platform != '0':
        match['platform'] = int(platform)
    if match:
        aggregation = [
            {
                "$group": {
                    "_id": None,  # 或者使用空字符串 "" 作为 _id，这取决于你的 MongoDB 版本
                    "count": {"$sum": 1}
                }
            }
        ]
        aggregation.insert(0, {'$match': match})
        result = StrategyLog.objects.mongo_aggregate(aggregation)
        try:
            count = next(result)['count']
        except StopIteration:
            count = 0
    else:
        count = StrategyLog.objects.count()
    data = {"count": count}
    return Response(data, status=status.HTTP_200_OK)


@api_view(["GET"])
def strategy_summary(request):
    # res = dict()
    # res["msg"] = "success"
    # res["status"] = 0
    channel = request.query_params.get('channel')
    if not channel:
        channel = DEFAULT_PLATFORM
    else:
        if channel not in list(map(str, range(1, 5))):
            res = Response({"msg": "channel参数错误", "data": {}},
                           status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            return res
        channel = int(channel)

    date_now = datetime.datetime.now()
    today_date_from = as_datetime(date_now.replace(hour=0, minute=0, second=0, microsecond=0))
    date_to = date_now.replace(hour=23, minute=59, second=59, microsecond=999)
    # 总数查询
    if channel:
        total_count = StrategyLog.objects.filter(platform=channel, username__isnull=False).count()
    else:
        total_count = StrategyLog.objects.filter(username__isnull=False).count()

    data = dict()
    if channel:
        today_total_count = StrategyLog.objects.filter(log_time__gt=today_date_from,
                                                       log_time__lt=date_to,
                                                       platform=channel).count()
    else:
        today_total_count = StrategyLog.objects.filter(log_time__gt=today_date_from,
                                                       log_time__lt=date_to).count()
    default = {'count': 0, 'android_count': 0, 'win_count': 0, 'web_count': 0, 'linux_count': 0}
    if total_count == 0:
        data['default'] = default
        data['today'] = default
        return Response(data, status=status.HTTP_200_OK)
    default['count'] = total_count
    queryset = StrategyLog.objects.mongo_aggregate([
        {'$match': {"username": {'$exists': True}}},
        {'$group': {'_id': '$platform', 'total_num': {'$sum': 1}}},
        {'$project': {'platform': '$_id', 'total_num': 1, '_id': 0}}
    ])
    for agg in queryset:
        if agg["platform"] == 1:
            default['android_count'] = agg["total_num"]
        elif agg["platform"] == 2:
            default['win_count'] = agg["total_num"]
        elif agg["platform"] == 3:
            default['web_count'] = agg["total_num"]
        elif agg["platform"] == 4:
            default['linux_count'] = agg["total_num"]
    data['default'] = default
    today = {'count': 0, 'android_count': 0, 'win_count': 0, 'web_count': 0, 'linux_count': 0}
    if today_total_count == 0:
        data['today'] = today
        return Response(data, status=status.HTTP_200_OK)
    today['count'] = today_total_count
    today_queryset = StrategyLog.objects.mongo_aggregate([
        {'$match': {"username": {'$exists': True}, 'log_time': {"$gt": today_date_from, "$lt": date_to}}},
        {'$group': {'_id': '$platform', 'total_num': {'$sum': 1}}},
        {'$project': {'platform': '$_id', 'total_num': 1, '_id': 0}}
    ])
    for today_agg in today_queryset:
        if today_agg["platform"] == 1:
            today['android_count'] = today_agg["total_num"]
        elif today_agg["platform"] == 2:
            today['win_count'] = today_agg["total_num"]
        elif today_agg["platform"] == 3:
            today['web_count'] = today_agg["total_num"]
        elif today_agg["platform"] == 4:
            today['linux_count'] = today_agg["total_num"]
    data['today'] = today
    return Response(data, status=status.HTTP_200_OK)


@api_view(["GET"])
def strategy_group(request):
    res = dict()
    res["msg"] = "success"
    res["status"] = 0
    date_to = as_datetime(datetime.datetime.now())
    date_from = as_datetime(date_to - datetime.timedelta(days=30))
    # 从strategyLog中根据username以及策略等级取出策略分值和总次数
    queryset = StrategyLog.objects.mongo_aggregate([
        {
            '$match': {
                "username": {'$exists': True},
                'log_time': {"$gt": date_from, "$lt": date_to}
            },
        },
        {
            '$group': {
                '_id': {
                    'user_name': '$username',
                    'level': '$meta.level'
                },
                'total_num': {'$sum': 1},
                'total_weight': {'$sum': '$meta.weight'}
            }
        },
        {
            '$project': {
                'user_name': "$_id.user_name",
                'level': "$_id.level",
                "total_num": "$total_num",
                "total_weight": "$total_weight"
            }
        }
    ]
    )
    # 构造一个基于user_name的字典
    user_name_set = set()
    user_info_dict = {}
    for query in queryset:
        user_name = query["user_name"]
        level = query["level"]
        total_num = query["total_num"]
        total_weight = query["total_weight"]
        user_name_set.add(query["user_name"])
        if not user_info_dict.get(user_name):
            user_info_dict[user_name] = dict()
        user_info_dict[user_name][level] = {"total_num": total_num, "total_weight": total_weight}
    # 从ZTPUser中取匹配数据
    strategy_group_info = dict()
    user_objs = ZTPUser.objects.filter(username__in=user_name_set).all()
    for obj in user_objs:
        user_name = obj.username
        group_id = obj.belong_to_id
        group = ZTPGroup.objects.get(id=group_id)
        if group.level not in (1, 2):
            continue
        elif group.level == 1:
            group = group.name
        elif group.level == 2:
            group = ZTPGroup.objects.get(id=group.parent_id).name
        if strategy_group_info.get(group) is None:
            user_info = user_info_dict[user_name]
            strategy_group_info[group] = dict()
            strategy_group_info[group]["high_nums"] = 0
            strategy_group_info[group]["mid_nums"] = 0
            strategy_group_info[group]["low_nums"] = 0
            strategy_group_info[group]["score"] = 0
        for i in user_info:
            if i == 3:  # 高危
                strategy_group_info[group]["high_nums"] += user_info[i]["total_num"]
            elif i == 2:  # 中危
                strategy_group_info[group]["mid_nums"] += user_info[i]["total_num"]
            elif i == 1:  # 低危
                strategy_group_info[group]["low_nums"] += user_info[i]["total_num"]
            strategy_group_info[group]["score"] += user_info[i]['total_weight']
    res["data"] = strategy_group_info
    return Response(res)
